package com.cdk8s.example.simplespringboot.service;

import com.cdk8s.example.simplespringboot.pojo.response.AppGetWebsiteInfoResponseDTO;
import com.cdk8s.example.simplespringboot.properties.TencentCosParamProperties;
import com.cdk8s.example.simplespringboot.properties.UploadParamProperties;
import com.cdk8s.example.simplespringboot.utils.FileUtil;
import com.cdk8s.example.simplespringboot.utils.JsoupUtil;
import com.cdk8s.example.simplespringboot.utils.StringUtil;
import com.cdk8s.example.simplespringboot.utils.SvgUtil;
import com.cdk8s.example.simplespringboot.utils.pojo.WebsiteInfo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class AppGetWebsiteInfoService {

	@Autowired
	private TencentCosService tencentCosService;

	@Autowired
	private TencentCosParamProperties tencentCosParamProperties;

	@Autowired
	private UploadParamProperties uploadParamProperties;


	// region=====================================查询业务 start=====================================

	// endregion=====================================查询业务 end=====================================

	// region=====================================操作业务 start=====================================


	@SneakyThrows
	public AppGetWebsiteInfoResponseDTO getWebsiteInfo(String gotoUrl) {
		AppGetWebsiteInfoResponseDTO responseDTO = new AppGetWebsiteInfoResponseDTO();

		WebsiteInfo websiteInfo = JsoupUtil.getWebsiteInfo(gotoUrl, null);
		if (null == websiteInfo || StringUtil.isBlank(websiteInfo.getIconUrl()) || StringUtil.isBlank(websiteInfo.getTitle())) {
			// 用 Selenium 方式再查询一次
			websiteInfo = getWebsiteInfoByFirefoxSelenium(gotoUrl);
			if (null == websiteInfo) {
				websiteInfo = getWebsiteInfoByChromeSelenium(gotoUrl);
			}
			if (null == websiteInfo) {
				return null;
			}
		}

		// 抓取成功
		String iconUrl = websiteInfo.getIconUrl();

		String cosFileRelativePath;
		if (StringUtil.isNotBlank(iconUrl) && StringUtil.endsWithIgnoreCase(iconUrl, "svg")) {
			// svg 需要先转换成 png 再上传到云存储
			// 重新生成一个 uuid 名，用新的 png 后缀
			String uuidFileName = FileUtil.getNewFileNameByUUID() + ".png";
			String fileFullPath = uploadParamProperties.getLocalUploadStoragePath() + File.separator + uuidFileName;

			// 开始转换
			SvgUtil.networkSvgToPngFile(iconUrl, fileFullPath, 32, 32);

			// 开始上传
			cosFileRelativePath = tencentCosService.uploadIconFromLocal(fileFullPath);
		} else {
			// 非 svg 后缀格式直接 url 上传（可能会抓不到，会返回 null）
			byte[] downloadFileByteData = FileUtil.downloadFileByUrl(iconUrl);
			cosFileRelativePath = tencentCosService.uploadIconFromIconUrl(iconUrl, downloadFileByteData);
		}

		if (StringUtil.isNotBlank(cosFileRelativePath)) {
			// 把 icon 图标转换成 cdn 地址
			iconUrl = tencentCosParamProperties.getFileCdnDomain() + cosFileRelativePath;
		}

		responseDTO.setUrlTitle(websiteInfo.getTitle());
		responseDTO.setIconUrl(iconUrl);
		responseDTO.setDescription(websiteInfo.getDescription());
		return responseDTO;
	}


	// endregion=====================================操作业务 end=====================================

	// region=====================================私有方法 start=====================================

	/**
	 * firefox 比较不容易被识别出来，推荐优先使用
	 *
	 * @param gotoUrl
	 * @return
	 */
	private WebsiteInfo getWebsiteInfoByFirefoxSelenium(String gotoUrl) {
		System.setProperty("webdriver.gecko.driver", "/usr/local/bin/geckodriver");
		WebDriver webDriver = null;
		try {
			FirefoxBinary firefoxBinary = new FirefoxBinary();
			firefoxBinary.addCommandLineOptions("--headless");
			FirefoxOptions options = new FirefoxOptions();
			options.setBinary(firefoxBinary);
			webDriver = new FirefoxDriver(options);//实例化

			webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
			webDriver.get(gotoUrl);

			String pageHtmlSource = webDriver.getPageSource();//获取网页全部信息
			Document document = Jsoup.parse(pageHtmlSource);
			return JsoupUtil.getWebsiteInfo(gotoUrl, document);
		} catch (Exception e) {
			log.error("------zch------firefox selenium 抓取报错 {}, <{}>", gotoUrl, e.getMessage());
		} finally {
			//使用完毕，关闭webDriver
			if (webDriver != null) {
				webDriver.quit();
			}
		}
		return null;
	}

	public Document getDocumentByFirefoxSelenium(String gotoUrl) {
		System.setProperty("webdriver.firefox.bin", "/Applications/Firefox.app/Contents/MacOS/firefox");
		System.setProperty("webdriver.gecko.driver", "/usr/local/bin/geckodriver");
		WebDriver webDriver = null;
		try {
			FirefoxBinary firefoxBinary = new FirefoxBinary();
            // 无浏览器模式
			firefoxBinary.addCommandLineOptions("--headless");
			FirefoxOptions options = new FirefoxOptions();
			options.setBinary(firefoxBinary);
            options.addPreference("general.useragent.override", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0");
			webDriver = new FirefoxDriver(options);

			webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
			webDriver.get(gotoUrl);

            // 禁用可能的防爬虫特征（如果抓取不到可以打开这两个注释试试看）
            //options.addPreference("dom.webdriver.enabled", false);
            //options.addPreference("useAutomationExtension", false);

            // 等待页面加载（现在很多网站的抓取都需要采用模拟人的行为）
            Thread.sleep(2000);

            // 模拟用户行为：滚动页面
            ((JavascriptExecutor) webDriver).executeScript("window.scrollBy(0, 1000);");

			String pageHtmlSource = webDriver.getPageSource();//获取网页全部信息
			return Jsoup.parse(pageHtmlSource);
		} catch (Exception e) {
			log.error("------zch------firefox selenium 抓取报错 {}, <{}>", gotoUrl, e.getMessage());
		} finally {
			//使用完毕，关闭webDriver
			if (webDriver != null) {
				webDriver.quit();
			}
		}
		return null;
	}

	private WebsiteInfo getWebsiteInfoByChromeSelenium(String gotoUrl) {
		System.setProperty("webdriver.chrome.driver", "/usr/local/bin/chromedriver");
		WebDriver webDriver = null;
		try {
			ChromeOptions options = new ChromeOptions();
			options.addArguments("--headless"); //无浏览器模式
			options.addArguments("--disable-gpu"); //linux 必须
			options.addArguments("--no-sandbox"); //linux 必须
			options.addArguments("--disable-extensions"); //linux 必须
			webDriver = new ChromeDriver(options);//实例化

			webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
			webDriver.get(gotoUrl);

			String pageHtmlSource = webDriver.getPageSource();//获取网页全部信息
			Document document = Jsoup.parse(pageHtmlSource);
			return JsoupUtil.getWebsiteInfo(gotoUrl, document);
		} catch (Exception e) {
			log.error("------zch------chrome selenium 抓取报错 {}, <{}>", gotoUrl, e.getMessage());
		} finally {
			//使用完毕，关闭webDriver
			if (webDriver != null) {
				webDriver.quit();
			}
		}
		return null;
	}


	// endregion=====================================私有方法 end=====================================


}
